package com.easyJava.builder;

import com.easyJava.bean.Constants;
import com.easyJava.bean.FieldInfo;
import com.easyJava.bean.TableInfo;
import com.easyJava.utils.BufferedWriterUtils;
import com.easyJava.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

@Slf4j
public class BuildServiceImpl {
    public static void execute(TableInfo tableInfo){
        File folder = new File(Constants.PATH_SERVICE_IMPL);
        folder.mkdirs();
        String serviceImplName = tableInfo.getBeanName() + Constants.SUFFIX_SERVICE_IMPL;
        String mapperName = tableInfo.getBeanName() + Constants.SUFFIX_MAPPER;

        File file = new File(folder, serviceImplName + Constants.FILE_SUFFIX_JAVA);

        try (
                OutputStream out = new FileOutputStream(file);
                OutputStreamWriter ow = new OutputStreamWriter(out, StandardCharsets.UTF_8);
                BufferedWriter bufferedWriter = new BufferedWriter(ow);
        ){
            BufferedWriterUtils bw = new BufferedWriterUtils(bufferedWriter);

            //生成包头
            bw.write("package " + Constants.PACKAGE_SERVICE_IMPL + ";");
            bw.newLine();

            //导包
            bw.write("import " + Constants.PACKAGE_PO +  "."  + tableInfo.getBeanName() + ";");
            bw.write("import " + Constants.PACKAGE_QUERY + "." + tableInfo.getBeanQueryName() + ";");
            bw.write("import " + Constants.PACKAGE_QUERY + ".SimplePage;");
            bw.write("import " + Constants.PACKAGE_ENUMS + ".PageSize;");
            bw.write("import " + Constants.PACKAGE_VO + ".PaginationResultVO;");
            bw.write("import " + Constants.PACKAGE_SERVICE + "." + tableInfo.getBeanName() + Constants.SUFFIX_SERVICE + ";");
            bw.write("import " + Constants.PACKAGE_MAPPER + "." + mapperName + ";");
            bw.newLine();
            bw.write("import java.util.List;");
            bw.write("import org.springframework.beans.factory.annotation.Autowired;");
            bw.write("import org.springframework.stereotype.Service;");
            bw.newLine();

            //生成注释
            BuildComment.createClassComment(bw, tableInfo.getComment() + "Service接口");
            //接口
            bw.write("@Service");
            bw.write("public class " + serviceImplName + " implements " + tableInfo.getBeanName() + Constants.SUFFIX_SERVICE +"{");
            bw.newLine();

            //注入mapper
            BuildComment.createFieldComment(bw, tableInfo.getBeanName() + "Mapper对象");
            bw.write("\t@Autowired");
            bw.write("\tprivate " + mapperName + " " + StringUtils.lowerFirstChar(mapperName) + ";");
            bw.newLine();

            //生成基础方法
            generateBaseMethod(bw, tableInfo);

            //根据唯一索引生成方法
            generateExtendMethod(bw, tableInfo);


            bw.write("}");
            bw.flush();
        }catch (Exception e){
            log.error("创建service失败:{}", e);
        }
    }

    private static void generateBaseMethod(BufferedWriterUtils bw, TableInfo tableInfo) throws IOException {
        bw.newLine();
        String queryObjName = StringUtils.lowerFirstChar(tableInfo.getBeanQueryName());
        String beanObjName = StringUtils.lowerFirstChar(tableInfo.getBeanName());
        String methodParam = tableInfo.getBeanName() + " "  + beanObjName;
        String methodQueryParam = tableInfo.getBeanQueryName() + " "  + queryObjName;
        String mapperName = StringUtils.lowerFirstChar(tableInfo.getBeanName() + Constants.SUFFIX_MAPPER);

        BuildComment.createMethodComment(bw, "新增");
        bw.write("\tpublic int add(" + methodParam + "){");
        bw.write("\t\treturn " + mapperName + "." + "insert(" + beanObjName + ");");
        bw.write("\t}");
        bw.newLine();

        BuildComment.createMethodComment(bw, "新增或修改");
        bw.write("\tpublic int addOrUpdate(" +  methodParam + "){");
        bw.write("\t\treturn " + mapperName + "." + "insertOrUpdate(" + beanObjName + ");");
        bw.write("\t}");
        bw.newLine();

        BuildComment.createMethodComment(bw, "批量新增");
        bw.write("\tpublic long addBatch(List<" + tableInfo.getBeanName() + "> list){");
        bw.write("\t\treturn " + mapperName + "." + "insertBatch(list);");
        bw.write("\t}");
        bw.newLine();

        BuildComment.createMethodComment(bw, "批量新增或修改");
        bw.write("\tpublic long addOrUpdateBatch(List<" + tableInfo.getBeanName() + "> list){");
        bw.write("\t\treturn " + mapperName + "." + "insertOrUpdateBatch(list);");
        bw.write("\t}");
        bw.newLine();

        BuildComment.createMethodComment(bw, "根据参数获取集合");
        bw.write("\tpublic List<" + tableInfo.getBeanName() + "> getList(" + methodQueryParam + "){");
        bw.write("\t\treturn " + mapperName + "." + "selectList(" + queryObjName + ");");
        bw.write("\t}");
        bw.newLine();

        BuildComment.createMethodComment(bw, "根据参数查询数量");
        bw.write("\tpublic long getCount(" + methodQueryParam + "){");
        bw.write("\t\treturn " + mapperName + "." + "selectCount(" + queryObjName + ");");
        bw.write("\t}");
        bw.newLine();

        BuildComment.createMethodComment(bw, "分页查询");
        bw.write("\tpublic PaginationResultVO<" + tableInfo.getBeanName() + "> getPageList(" + methodQueryParam + "){");
        bw.write("\t\tlong count = this.getCount(" + queryObjName + ");");
        bw.write("\t\tint pageSize = " + queryObjName + ".getPageSize()==null ? PageSize.SIZE10.getSize() : " + queryObjName + ".getPageSize();");
        bw.write("\t\tSimplePage page = new SimplePage(" + queryObjName + ".getPageNo(), count, pageSize);");
        bw.write("\t\t" + queryObjName + ".setSimplePage(page);");
        bw.write("\t\tList<" + tableInfo.getBeanName() + "> list = this.getList(" + queryObjName + ");");
        bw.write("\t\tPaginationResultVO<" + tableInfo.getBeanName() + "> result = new PaginationResultVO<>(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);");
        bw.write("\t\treturn result;");
        bw.write("\t}");
        bw.newLine();
    }

    private static void generateExtendMethod(BufferedWriterUtils bw, TableInfo tableInfo) throws IOException {
        String beanObjName = StringUtils.lowerFirstChar(tableInfo.getBeanName());
        String mapperName = StringUtils.lowerFirstChar(tableInfo.getBeanName() + Constants.SUFFIX_MAPPER);
        Map<String, List<FieldInfo>> indexMap = tableInfo.getIndexMap();
        for(Map.Entry<String, List<FieldInfo>> entry : indexMap.entrySet()){
            List<FieldInfo> fieldInfoList = entry.getValue();
            StringBuffer methodNameSB = new StringBuffer();
            StringBuffer paramSB = new StringBuffer();
            StringBuffer invokeParamSB = new StringBuffer();
            int index = 0;
            for(FieldInfo fieldInfo : fieldInfoList){
                index++;
                methodNameSB.append(StringUtils.upperFirstChar(fieldInfo.getBeanFieldName()));
                paramSB.append(fieldInfo.getJavaType()  + " "  + fieldInfo.getBeanFieldName());
                invokeParamSB.append(fieldInfo.getBeanFieldName());
                if(index < fieldInfoList.size()){
                    methodNameSB.append("And");
                    paramSB.append(", ");
                    invokeParamSB.append(", ");
                }
            }
            String methodName = methodNameSB.toString();
            String param = paramSB.toString();
            String invokeParam = invokeParamSB.toString();

            BuildComment.createMethodComment(bw, "根据" + methodName + "查询");
            bw.write("\tpublic " + tableInfo.getBeanName() + " getBy" + methodName + "(" + param + "){");
            bw.write("\t\treturn " + mapperName + ".selectBy" + methodName + "(" + invokeParam + ");");
            bw.write("\t}");
            bw.newLine();

            BuildComment.createMethodComment(bw, "根据" + methodName + "修改");
            bw.write("\tpublic int" + " updateBy" + methodName + "(" + tableInfo.getBeanName() + " " + beanObjName + ", " + param + "){");
            bw.write("\t\treturn " + mapperName + ".updateBy" + methodName + "("  + beanObjName + ", "  + invokeParam + ");");
            bw.write("\t}");
            bw.newLine();

            BuildComment.createMethodComment(bw, "根据" + methodName + "删除");
            bw.write("\tpublic int" + " deleteBy" + methodName + "(" + param + "){");
            bw.write("\t\treturn " + mapperName + ".deleteBy" + methodName + "(" + invokeParam + ");");
            bw.write("\t}");
            bw.newLine();
        }
    }
}
